# encoding:utf-8

import json
import logging
import os
import pickle
import copy

from common.log import logger

# 定义所有可用的配置项，使用小写字母
available_setting = {
    "api_key": "",
    "base_url": "",
    "model": "",
    "open_ai_api_key": "",
    "open_ai_api_base": "",
    "proxy": "",
    "model": "",
    "bot_type": "",
    "use_azure_chatgpt": False,
    "azure_deployment_id": "",
    "azure_api_version": "",
    "single_chat_prefix": [],
    "single_chat_reply_prefix": "",
    "single_chat_reply_suffix": "",
    "group_chat_prefix": [],
    "no_need_at": False,
    "group_chat_reply_prefix": "",
    "group_chat_reply_suffix": "",
    "group_chat_keyword": [],
    "group_at_off": False,
    "group_name_white_list": [],
    "group_name_keyword_white_list": [],
    "group_chat_in_one_session": [],
    "nick_name_black_list": [],
    "group_welcome_msg": "",
    "trigger_by_self": False,
    "text_to_image": "",
    "dalle3_image_style": "",
    "dalle3_image_quality": "",
    "azure_openai_dalle_api_base": "",
    "azure_openai_dalle_api_key": "",
    "azure_openai_dalle_deployment_id": "",
    "image_proxy": False,
    "image_create_prefix": [],
    "concurrency_in_session": 1,
    "image_create_size": "",
    "group_chat_exit_group": False,
    "expires_in_seconds": 3600,
    "character_desc": "",
    "conversation_max_tokens": 1000,
    "rate_limit_chatgpt": 20,
    "rate_limit_dalle": 50,
    "temperature": 0.9,
    "top_p": 1,
    "frequency_penalty": 0,
    "presence_penalty": 0,
    "request_timeout": 180,
    "timeout": 120,
    "baidu_wenxin_model": "",
    "baidu_wenxin_api_key": "",
    "baidu_wenxin_secret_key": "",
    "baidu_wenxin_prompt_enabled": False,
    "xunfei_app_id": "",
    "xunfei_api_key": "",
    "xunfei_api_secret": "",
    "xunfei_domain": "",
    "xunfei_spark_url": "",
    "claude_api_cookie": "",
    "claude_uuid": "",
    "claude_api_key": "",
    "qwen_access_key_id": "",
    "qwen_access_key_secret": "",
    "qwen_agent_key": "",
    "qwen_app_id": "",
    "qwen_node_id": "",
    "dashscope_api_key": "",
    "gemini_api_key": "",
    "wework_smart": True,
    "speech_recognition": True,
    "group_speech_recognition": False,
    "voice_reply_voice": False,
    "always_reply_voice": False,
    "voice_to_text": "openai",
    "text_to_voice": "openai",
    "text_to_voice_model": "tts-1",
    "tts_voice_id": "",
    "baidu_app_id": "",
    "baidu_api_key": "",
    "baidu_secret_key": "",
    "baidu_dev_pid": 1536,
    "azure_voice_api_key": "",
    "azure_voice_region": "japaneast",
    "xi_api_key": "",
    "xi_voice_id": "",
    "chat_time_module": False,
    "chat_start_time": "00:00",
    "chat_stop_time": "24:00",
    "translate": "baidu",
    "baidu_translate_app_id": "",
    "baidu_translate_app_key": "",
    "hot_reload": False,
    "wechaty_puppet_service_token": "",
    "wechatmp_token": "",
    "wechatmp_port": 8080,
    "wechatmp_app_id": "",
    "wechatmp_app_secret": "",
    "wechatmp_aes_key": "",
    "wechatcom_corp_id": "",
    "wechatcomapp_token": "",
    "wechatcomapp_port": 9898,
    "wechatcomapp_secret": "",
    "wechatcomapp_agent_id": "",
    "wechatcomapp_aes_key": "",
    "feishu_port": 80,
    "feishu_app_id": "",
    "feishu_app_secret": "",
    "feishu_token": "",
    "feishu_bot_name": "",
    "dingtalk_client_id": "",
    "dingtalk_client_secret": "",
    "dingtalk_card_enabled": False,
    "clear_memory_commands": [],
    "channel_type": "",
    "subscribe_msg": "",
    "debug": False,
    "appdata_dir": "",
    "plugin_trigger_prefix": "$",
    "use_global_plugin_config": False,
    "max_media_send_count": 3,
    "media_send_interval": 1,
    "zhipu_ai_api_key": "",
    "zhipu_ai_api_base": "",
    "moonshot_api_key": "",
    "moonshot_base_url": "",
    "use_linkai": False,
    "linkai_api_key": "",
    "linkai_app_code": "",
    "linkai_api_base": "https://api.link-ai.tech",
    "Minimax_api_key": "",
    "Minimax_group_id": "",
    "Minimax_base_url": "",
    "web_port": 9899,
}


class Config(dict):
    def __init__(self, d=None):
        super().__init__()
        if d is None:
            d = {}
        for k, v in d.items():
            self[k] = v
        self.user_datas = {}

    def __getitem__(self, key):
        if key not in available_setting:
            raise Exception("key {} not in available_setting".format(key))
        return super().__getitem__(key)

    def __setitem__(self, key, value):
        if key not in available_setting:
            raise Exception("key {} not in available_setting".format(key))
        return super().__setitem__(key, value)

    def get(self, key, default=None):
        try:
            return self[key]
        except KeyError:
            return default
        except Exception as e:
            raise e

    def get_user_data(self, user) -> dict:
        if self.user_datas.get(user) is None:
            self.user_datas[user] = {}
        return self.user_datas[user]

    def load_user_datas(self):
        try:
            data_path = get_appdata_dir()
            with open(os.path.join(data_path, "user_datas.pkl"), "rb") as f:
                self.user_datas = pickle.load(f)
                logger.info("[Config] User datas loaded.")
        except FileNotFoundError:
            logger.info("[Config] User datas file not found, ignore.")
        except Exception as e:
            logger.info("[Config] User datas error: {}".format(e))
            self.user_datas = {}

    def save_user_datas(self):
        try:
            data_path = get_appdata_dir()
            with open(os.path.join(data_path, "user_datas.pkl"), "wb") as f:
                pickle.dump(self.user_datas, f)
                logger.info("[Config] User datas saved.")
        except Exception as e:
            logger.info("[Config] User datas error: {}".format(e))


config = Config()


def drag_sensitive(config):
    try:
        if isinstance(config, str):
            conf_dict = json.loads(config)
            conf_dict_copy = copy.deepcopy(conf_dict)
            for key in conf_dict_copy:
                if "key" in key or "secret" in key:
                    if isinstance(conf_dict_copy[key], str):
                        conf_dict_copy[key] = conf_dict_copy[key][0:3] + "*" * 5 + conf_dict_copy[key][-3:]
            return json.dumps(conf_dict_copy, indent=4)

        elif isinstance(config, dict):
            config_copy = copy.deepcopy(config)
            for key in config_copy:
                if "key" in key or "secret" in key:
                    if isinstance(config_copy[key], str):
                        config_copy[key] = config_copy[key][0:3] + "*" * 5 + config_copy[key][-3:]
            return config_copy
    except Exception as e:
        logger.exception(e)
        return config
    return config


def load_config():
    global config
    config_path = "./config.json"
    if not os.path.exists(config_path):
        logger.info("配置文件不存在，将使用 config-template.json 模板")
        config_path = "./config-template.json"

    with open(config_path, "r", encoding="utf-8") as f:
        config_str = f.read()

    logger.debug("[INIT] config str: {}".format(drag_sensitive(config_str)))

    config_dict = json.loads(config_str)
    config = Config(config_dict)

    for name, value in os.environ.items():
        name = name.lower()
        if name in available_setting:
            logger.info("[INIT] override config by environ args: {}={}".format(name, value))
            if value.lower() == "true":
                config[name] = True
            elif value.lower() == "false":
                config[name] = False
            else:
                config[name] = value

    if config.get("debug", False):
        logger.setLevel(logging.DEBUG)
        logger.debug("[INIT] set log level to DEBUG")

    logger.info("[INIT] load config: {}".format(drag_sensitive(config)))

    config.load_user_datas()


def get_root():
    return os.path.dirname(os.path.abspath(__file__))


def read_file(path):
    with open(path, mode="r", encoding="utf-8") as f:
        return f.read()


def conf():
    return config


def get_appdata_dir():
    data_path = os.path.join(get_root(), conf().get("appdata_dir", ""))
    if not os.path.exists(data_path):
        os.makedirs(data_path)
    return data_path


def subscribe_msg():
    trigger_prefix = conf().get("single_chat_prefix", [""])[0]
    msg = conf().get("subscribe_msg", "")
    return msg.format(trigger_prefix=trigger_prefix)


plugin_config = {}


def write_plugin_config(pconf: dict):
    global plugin_config
    for k in pconf:
        plugin_config[k.lower()] = pconf[k]


def remove_plugin_config(name: str):
    global plugin_config
    plugin_config.pop(name.lower(), None)


def pconf(plugin_name: str) -> dict:
    return plugin_config.get(plugin_name.lower())


global_config = {"admin_users": []}
